package concurrent.thread;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Random;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @program JavaBase
 * @description:
 * @author: zhanglu
 * @create: 2021-05-09 18:17:00
 */
public class RandomThreadLocalRandomTest {

    /**
     *  单线程：4101231130｜4101231130
     *  - 首先根据老的种子生成新的种子
     *  - 根据新的种子来计算新的随机数
     */
    @Test
    public void test01(){
//        AtomicInteger
//        Vector
//        ArrayList
//        ConcurrentHashMap
        Random random = new Random(8);
        for (int i = 0; i < 10; i++) {
            System.out.print(random.nextInt(5));
        }
    }

    /**
     * 多线程：4112110303｜4021110313
     * - 考虑到多线程场景下，多个子线程拿到的老种子是一样的，故计算的新种子也是一样的，生成的随机数也不是真正的随机，
     *  所以Random里面增加了CAS操作来保证在多线程场景下，当多个子线程拿到的老种子一样时，只有一个线程计算后可以更新成功，其他的自旋重试
     *  这样能解决问题，保证随机性，但是带来性能问题，故产生了ThreadLocalRandom
     */
    @Test
    public void test02(){
        Random random = new Random(8);
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                try {
                    TimeUnit.MICROSECONDS.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("---");
                System.out.println(random.nextInt(5));
            }).start();
        }
        while (true){}
    }

    public static void main(String[] args) {
        new RandomThreadLocalRandomTest().test02();
    }

    /**
     *  保证随机性，且性能得以保证
     *  原理：与ThreadLocal一样，各个线程内部维护一个种子，计算的时候用线程自己的，而不是想Random，是多个线程使用的种子是共享变量
     *  补充：多线程下计算新种子时根据自己线程内维护的种子变量进行更新。
     */
    @Test
    public void test03(){
        ThreadLocalRandom random = ThreadLocalRandom.current();
        for (int i = 0; i < 10; i++) {
            System.out.print(random.nextInt(5));
        }
    }

}
